package cn.wildfire.chat.app.extendsion.widgets;

import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.sourcemuch.im.caiba.R;

import java.security.InvalidKeyException;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.recyclerview.widget.RecyclerView;
import cn.wildfire.chat.app.extendsion.classes.Pointer;

/**
 * Create by HEKE, 2019/9/18 16:56
 * TODO 触摸事件重新分配定制控件
 */
public class DispenseRecyclerView extends RecyclerView {

    /**
     * 当前选中子件
     */
    protected View selectedView;

    /**
     * 左右滑动是否禁止操作
     */
    protected boolean aroundLRSlidable = true;

    /**
     * 回调选中滑动子项接口
     */
    protected OnDispenseTouchSelectListener onDispenseTouchSelectListener;

    private void initAttrs() {
        slidePiceValue = getResources().getDimensionPixelSize(R.dimen.y10);
        minSlideDist = getResources().getDimensionPixelSize(R.dimen.y10);
        maxSlideDist = getResources().getDimensionPixelSize(R.dimen.y150);//ll取消置顶改y300
        slideItemWidth = maxSlideDist / slideSize;
    }

    public DispenseRecyclerView(@NonNull Context context) {
        super(context);
        initAttrs();
    }

    public DispenseRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initAttrs();
    }

    public DispenseRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initAttrs();
    }

    public void setOnDispenseTouchSelectListener(OnDispenseTouchSelectListener onDispenseTouchSelectListener) {
        this.onDispenseTouchSelectListener = onDispenseTouchSelectListener;
    }

    /**
     * 判断当前是否可以左右滑动
     */
    public boolean isAroundLRSlidable() {
        return aroundLRSlidable;
    }

    /**
     * 设置是否允许左右滑动
     */
    public void setAroundLRSlidable(boolean aroundLRSlidable) {
        this.aroundLRSlidable = aroundLRSlidable;
    }

    /**
     * 获取选中控件
     */
    public View getSelectedView() {
        return selectedView;
    }

    /**
     * 触摸按下时间，标记点，最小移动距离
     */
    protected long downTime;
    protected Pointer firstDownPointer;
    protected Pointer downPointer;
    protected Pointer movePointer;
    protected Pointer upPointer;
    protected float minSlideDist;
    /**
     * TODO 最大允许滑动距离，根据实际显示子项可滑动距离进行设置
     */
    protected float maxSlideDist;
    /**
     * TODO 滑出的每个子件的宽度(目前滑动子项的宽度都为等宽，若有需求可扩展)
     */
    protected float slideItemWidth;

    /**
     * 动画滑动单位数值
     */
    protected int slidePiceValue;

    /**
     * TODO 滑出子项总数量
     */
    protected int slideSize = 1;//ll置顶取消置顶，原来2项
    /**
     * 当前总移动X偏距
     */
    protected float totalSlide;

    /**
     * 绑定可触摸控件的id
     */
    protected int[] itemClickIds;

    /**
     * 获取最大滑动子项总宽度
     */
    public float getMaxSlideDist() {
        return maxSlideDist;
    }

    /**
     * 设置最大滑动子项总宽度
     *
     * @param maxSlideDist
     */
    public void setMaxSlideDist(float maxSlideDist) {
        this.maxSlideDist = maxSlideDist;
    }

    /**
     * 获取滑动子项数量
     */
    public int getSlideSize() {
        return slideSize;
    }

    /**
     * 设置滑动选项总个数
     *
     * @param slideSize
     */
    public void setSlideSize(int slideSize) {
        this.slideSize = slideSize;
    }

    /**
     * 设置动画间隔最小单位
     *
     * @param slidePiceValue
     */
    public void setSlidePiceValue(int slidePiceValue) {
        this.slidePiceValue = slidePiceValue;
    }

    /**
     * 绑定可点击的子项中的子控件id
     *
     * @param itemClickIds
     */
    public void bindItemClickIds(int[] itemClickIds) {
        this.itemClickIds = itemClickIds;
    }

    private boolean useSuper;

    /**
     * 强制允许滚动事件执行标志
     */
    protected boolean froceAllowSlidAnimation;

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                float dx = ev.getX();
                float dy = ev.getY();
                if (firstDownPointer == null) {
                    firstDownPointer = new Pointer(dx, dy);
                } else {
                    firstDownPointer.x = dx;
                    firstDownPointer.y = dy;
                }
                if (downPointer == null) {
                    downPointer = new Pointer(dx, dy);
                } else {
                    downPointer.x = dx;
                    downPointer.y = dy;
                }
                selectedView = getClickedView(downPointer.x, downPointer.y);
                // 子项中的内部控件点击检测，若绑定控件被点中，直接下传事件
                if (onDispenseTouchSelectListener != null && selectedView != null) {
                    View clickItemChildView = checkClickChindView(dx, dy);
                    if (clickItemChildView != null) {
                        onDispenseTouchSelectListener.checkClickChildView(clickItemChildView, selectedView, clickItemChildView.getId());
                        return false;
                    }
                } else {
                    if (selectedView == null) {
                        forceResetSlideValue();
                        return false;
                    }
                }
                downTime = System.currentTimeMillis();
                useSuper = false;
                resetSlideValue();
                return true;
            case MotionEvent.ACTION_MOVE:
                //ll第一项禁止滑动功能
                if (positionClicked == 0) {
                    return true;
                }

                float mx = ev.getX();
                float my = ev.getY();
                try {
                    if (movePointer == null) {
                        movePointer = new Pointer(mx + "," + my);
                    } else {
                        movePointer.x = mx;
                        movePointer.y = my;
                    }
                    float poorX = downPointer.x - movePointer.x;
                    float absOffsetX = downPointer.offset("x", movePointer);
                    float absOffsetY = downPointer.offset("y", movePointer);
                    if (absOffsetY < absOffsetX) {
                        if (absOffsetX >= minSlideDist) {
                            slideItemView(poorX);
                            downPointer.x = movePointer.x;
                            downPointer.y = movePointer.y;
                        }
                    } else {
                        // 垂直滑动时，判断差距距离区分点击事件，手动下传触摸事件给父类(父类即可有效执行)
                        if (Math.abs(absOffsetY - absOffsetX) >= minSlideDist / 3) {
                            if (!useSuper) {
                                useSuper = true;
                                super.dispatchTouchEvent(MotionEvent.obtain(downTime, downTime + 10,
                                        MotionEvent.ACTION_DOWN, firstDownPointer.x, firstDownPointer.y, 0));
                            }
                            super.dispatchTouchEvent(ev);
                        }
                    }
                } catch (InvalidKeyException e) {
                    e.printStackTrace();
                }
                break;
            case MotionEvent.ACTION_UP:
                if (useSuper) {
                    return false;
                }
                float ux = ev.getX();
                float uy = ev.getY();
                long upTime = System.currentTimeMillis();
                try {
                    if (upPointer == null) {
                        upPointer = new Pointer(ux + "," + uy);
                    } else {
                        upPointer.x = ux;
                        upPointer.y = uy;
                    }
                    float dist = firstDownPointer.dist(upPointer);
                    float upoorX = firstDownPointer.x - upPointer.x;
                    float offsetX = firstDownPointer.offset("x", upPointer);
                    /**
                     * 短按事件分发
                     * */
                    if (dist < minSlideDist && offsetX < minSlideDist && (upTime - downTime) <= 350L) {
                        if (selectedView != null) {
                            if (totalSlide > 0) {
                                int selectViewWidth = selectedView.getMeasuredWidth();
                                int minX = (int) (selectViewWidth - totalSlide);
                                int slideShowSize = (int) (totalSlide / slideItemWidth);
                                if (slideShowSize == 0) {
                                    if (upPointer.x >= minX) {
                                        if (onDispenseTouchSelectListener != null) {
                                            onDispenseTouchSelectListener.clieckSlide(selectedView, 0);
                                            forceResetSlideValue();
                                        }
                                    }
                                } else {
                                    float itemGapSize = upPointer.x - minX;
                                    if (itemGapSize > 0) {
                                        int position = (int) (itemGapSize / slideItemWidth);
                                        if (onDispenseTouchSelectListener != null) {
                                            onDispenseTouchSelectListener.clieckSlide(selectedView, position);
                                            forceResetSlideValue();
                                        }
                                    } else {
                                        selectedView.performClick();
                                    }
                                }
                            } else {
                                selectedView.performClick();
                            }
                        }
                    } else {
                        /**
                         * 设置当前选中View的滑动动画事件
                         * */
                        if (selectedView != null && dist > minSlideDist && offsetX > minSlideDist) {
                            int current = selectedView.getScrollX();
                            if (upoorX > 0) {
                                if (current >= maxSlideDist / 3) {
                                    new SlideAnimation(selectedView, current, maxSlideDist, slidePiceValue);
                                } else {
                                    new SlideAnimation(selectedView, current, 0, slidePiceValue);
                                }
                            } else {
                                new SlideAnimation(selectedView, current, 0, slidePiceValue);
                            }
                        }
                    }
                } catch (InvalidKeyException e) {
                    e.printStackTrace();
                }
                break;
            default:
                break;
        }
        return true;
    }

    static int positionClicked = 0;

    /**
     * 根据触摸位置获取当前选中子件
     *
     * @param x
     * @param y
     * @return
     */
    protected View getClickedView(float x, float y) {
        try {
            int itemBegainY = 0;
            for (int i = 0; i < getChildCount(); i++) {
                positionClicked = i;
                View view = getChildAt(i);
                int viewHeight = view.getMeasuredHeight();
                if (y >= itemBegainY && y <= (itemBegainY + viewHeight)) {
                    totalSlide = view.getScrollX();
                    return view;
                }
                itemBegainY += viewHeight;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 检测点击到的子项中的子控件
     *
     * @param x
     * @param y
     * @return
     */
    protected View checkClickChindView(float x, float y) {
        if (selectedView == null || itemClickIds == null) {
            return null;
        }
        try {
            // 获取自身控件在整个屏幕上的位置信息
            Rect selfRect = new Rect();
            getGlobalVisibleRect(selfRect);
            // 遍历查询点击子控件
            for (int i = 0; i < itemClickIds.length; i++) {
                View childView = selectedView.findViewById(itemClickIds[i]);
                if (childView != null) {
                    Rect childRect = new Rect();
                    childView.getGlobalVisibleRect(childRect);
                    float ctx = childRect.left;
                    float cty = childRect.top - selfRect.top;
                    int childWidth = childView.getMeasuredWidth();
                    int childHeight = childView.getMeasuredHeight();
                    // 文本控件显示文本上下是颠倒的，与文字绘制顺序方向有关
                    if (childView instanceof AppCompatTextView) {
                        cty = cty - childHeight;
                    }
                    if (x >= ctx && x <= (ctx + childWidth) && y >= cty && y <= (cty + childHeight)) {
                        return childView;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取当前正在显示滑动内容的子控件
     */
    private View[] getSlideShowView() {
        View[] show = new View[2];
        try {
            int count = 0;
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                if (child.getScrollX() > 0) {
                    if (count < show.length) {
                        show[count] = child;
                        count++;
                    }
                }
            }
            if (show[0] == null && show[1] == null) {
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return show;
    }

    /**
     * 滑动子控件
     *
     * @param poorX
     */
    public void slideItemView(float poorX) {
        if (selectedView == null) {
            return;
        }
        if (onDispenseTouchSelectListener != null && !onDispenseTouchSelectListener.isItemViewAllowSlide(selectedView)) {
            return;
        }
        try {
            totalSlide += poorX;
            if (totalSlide <= 0) {
                totalSlide = 0;
            } else if (totalSlide >= maxSlideDist) {
                totalSlide = maxSlideDist;
            }
            selectedView.setScrollX((int) totalSlide);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置是否允许强制执行动画效果
     *
     * @param froceAllowSlidAnimation
     */
    public void setFroceAllowSlidAnimation(boolean froceAllowSlidAnimation) {
        this.froceAllowSlidAnimation = froceAllowSlidAnimation;
    }

    /**
     * 发送设置子件滚动事件
     *
     * @param view
     * @param value
     */
    private void postViewScroll(View view, float value) {
        if (view == null) {
            return;
        }
        if (!froceAllowSlidAnimation) {
            if (onDispenseTouchSelectListener != null && !onDispenseTouchSelectListener.isItemViewAllowSlide(view)) {
                return;
            }
        }
        view.post(new Runnable() {
            @Override
            public void run() {
                int val = (int) value;
                view.setScrollX(val);
                if (val <= 0) {
                    froceAllowSlidAnimation = false;
                }
            }
        });
    }

    /**
     * 重置滑动项显示
     */
    protected void resetSlideValue() {
        View[] showView = getSlideShowView();
        if (showView == null) {
            return;
        }
        for (int i = 0; i < showView.length; i++) {
            View view = showView[i];
            if (view != null && !selectedView.equals(view)) {
                new SlideAnimation(view, view.getScrollX(), 0, slidePiceValue);
            }
        }
    }

    /**
     * 强制复原滑动长度
     */
    public void forceResetSlideValue() {
        View[] showView = getSlideShowView();
        if (showView != null) {
            for (int i = 0; i < showView.length; i++) {
                View view = showView[i];
                if (view != null) {
                    new SlideAnimation(view, view.getScrollX(), 0, slidePiceValue);
                }
            }
        }
        totalSlide = 0;
    }

    /**
     * Create by HEKE, 2019/9/23 10:05
     * TODO 滑动动画线程
     */
    private class SlideAnimation extends Thread {

        private float current;
        private float tartget;
        private float distGap;
        private boolean isSetShow;
        private float minValue;

        private View showView;

        public SlideAnimation(View view, float current, float tartget, int piceGap) {
            this.current = current;
            this.tartget = tartget;
            this.distGap = Math.abs(current - tartget);
            this.minValue = piceGap;
            this.isSetShow = (this.tartget > this.current);
            this.showView = view;
            start();
        }

        @Override
        public void run() {
            super.run();
            try {
                if (showView == null) {
                    return;
                }
                if (distGap <= minValue) {
                    postViewScroll(showView, tartget);
                    return;
                }
                while (true) {
                    Thread.sleep(10);
                    if (isSetShow) {
                        current += minValue;
                        if (current > maxSlideDist) {
                            current = maxSlideDist;
                        }
                        postViewScroll(showView, current);
                        if (current >= maxSlideDist) {
                            return;
                        }
                    } else {
                        current -= minValue;
                        if (current < 0) {
                            current = 0;
                        }
                        postViewScroll(showView, current);
                        if (current <= 0) {
                            return;
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * Create by HEKE, 2019/9/18 19:10
     * TODO 控件的滑动触摸事件分发回调接口
     */
    public interface OnDispenseTouchSelectListener {
        void clieckSlide(View view, int position);

        boolean isItemViewAllowSlide(View view);

        void checkClickChildView(View clickView, View rootView, int id);
    }

}
